const { Parser } = require("../lib/ddm");
const { isFunction } = require("../lib/helper");
const { isRegularTag } = require("./util");

class Tag {
    constructor() {
        this.regularTags = [];
        this.selfCloseTags = ["br", "hr", "img", "input", "param", "link", "meta", "area", "base", "basefont", "param", "col", "frame", "embed", "keygen", "source"];
        this.tags = {}
    }

    get(tagName) {
        if (tagName) {
            return this.tags[tagName];
        } else {
            return this.tags;
        }
    }

    set(tagName, generator) {
        this.tags[tagName] = generator;
        if (!isFunction(generator)) {
            if (generator.selfClose) {
                this.selfCloseTags.push(tagName);
            }
        }
    }

    has(tagName) {
        return this.get(tagName) !== undefined;
    }

    remove(viewClass) {
        Reflect.ownKeys(this.tags).filter(tagName => this.tags[tagName] === viewClass).forEach(tagName => delete this.tags[tagName]);
    }

    isRegularTag(tagName) {
        let result = true;
        if (this.regularTags.indexOf(tagName) === -1) {
            if (isRegularTag(tagName)) {
                this.regularTags.push(tagName);
            } else {
                result = false;
            }
        }
        return result;
    }
}

class DDMVariables {
    constructor() {
        this._defaultMacros = {
            self({ props, context }) {
                return { template: context.getTemplateStr(), data: props.parameter };
            },
            custom({ bodyStr, props, events, attrs, option, env, context }) {
                let template = "";
                let tagName = props.customTagName, generator = option ? (option.tags ? option.tags[tagName] : null) : null;
                if (!generator) {
                    generator = env.ddm.tags.get(tagName);
                }
                if (generator.template) {
                    template = generator.template({
                        bodyStr,
                        props,
                        events,
                        attrs,
                        option,
                        context,
                        env,
                        generateOption: generator.option
                    });
                } else {
                    throw Error(`[ada] tag [${tagName}] can not defined with function of generate template`);
                }
                return { template, data: props };
            }
        };
        this._defaultAssignDirectives = {
            html(content) {
                return content;
            }
        };
        this._defaultFns = {
            join: (...args) => {
                return args
                    .filter(a => typeof a === 'string')
                    .map(a => a.trim())
                    .filter(a => a !== '')
                    .join(' ');
            }
        };
        this._defaultPropMacros = {};
        this._tags = new Tag();
    }

    get tags() {
        return this._tags;
    }

    get defaultMacros() {
        return this._defaultMacros;
    }

    get defaultAssignDirectives() {
        return this._defaultAssignDirectives
    }

    get defaultPropMacros() {
        return this._defaultPropMacros;
    }

    get defaultFns() {
        return this._defaultFns;
    }

    setDefaultMacro(key, fn) {
        this._defaultMacros[key] = fn;
        return null;
    }

    setDefaultTag(name, info) {
        this.tags.set(name, info);
    }

    setDefaultIcon(icon) {
        return this.setDefaultTag(icon.name, icon.info);
    }

    setDefaultAssignDirective(key, fn) {
        this._defaultAssignDirectives[key] = fn;
        (function (key) {
            Parser.beautySyntax.syntaxs[key] = function (str) {
                return `<%=assign(${key},${str.filter(a => !!a).join(",")});%>`;
            };
        })(key);
        return null;
    }

    setDefaultFunction(name, fn) {
        this._defaultFns[name] = fn;
        return this;
    }

    setDefaultPropMacro(name, fn) {
        this._defaultPropMacros[name] = fn;
    }
}

module.exports = DDMVariables;